namespace Sinject
{
	/*
	void *hkAllocateEntry(void)
	{	
		if(InitPhase)
		{
			return false;
		}
		else
		{
			pHeap = RtlAllocateAlignedHeap(sizeof(CLLHook),MEMORY_ALLOCATION_ALIGNMENT);
			PCLLHook pCLL = (PCLLHook)pHeap;
			pCLL->pHeap = pHeap;
			if(pCLL)
			{
				if(!InitPhase)
				{
					pFirstEntry = RtlInterlockedPushEntrySList(pListHead,&(pCLL->HookEntry));
					InitPhase++;
				}
				pListEntry = RtlInterlockedPushEntrySList(pListHead,&(pCLL->HookEntry));
				return (void*)pCLL;
			}
			return false;
		}
	}
	__checkReturn bool hkInitialize(__out CLLHook* pCLL )
	{
		if(InitPhase > 0)
		{
			return false;
		}
		hHeap = RtlCreateHeap(HEAP_GROWABLE|HEAP_ZERO_MEMORY,0,0,0,0,0);//64 pages reserved, 1 page allocated
  		if(hHeap != INVALID_HANDLE_VALUE && hHeap != 0)
  		{	
			pListHead = (PSLIST_HEADER)RtlAllocateAlignedHeap(sizeof(SLIST_HEADER),MEMORY_ALLOCATION_ALIGNMENT);
			if(!pListHead)
			{
				return false;
			}
			RtlInitializeSListHead(pListHead);
			if(pListHead)
			{
				*pCLL = *(CLLHook*)hkAllocateEntry();
				if(pCLL != 0)
				{
					return true;
				}
			}
		}
		return false;	
	}
__checkReturn bool hkSetHookParams(__in_opt wchar_t* TargetName,__in LPVOID TargetAddr,__in LPVOID HookAddr,__in DWORD HkSz,__in BYTE Opcode,__inout CLLHook *HkStruct)
{
	if(Opcode && HkSz && HookAddr && TargetAddr && InitPhase)
	{
		if(InitPhase == 1)
		{
			HkStruct->Opcode = Opcode;
			HkStruct->hkTAddress = (DWORD)TargetAddr;
			HkStruct->hkAddress = (DWORD)HookAddr;
			HkStruct->hkSz = HkSz;
			HkStruct->Index = InitPhase;
			InitPhase++;
			if(TargetName != 0)
			{
				hkSetTargetExeName(TargetName);
				HkStruct->TProcessId = (DWORD)GetPidByName(TargetName);
			}
			return true;
		}
		else
		{
			HkStruct->Opcode = Opcode;
			HkStruct->hkTAddress = (DWORD)TargetAddr;
			HkStruct->hkAddress = (DWORD)HookAddr;
			HkStruct->hkSz = HkSz;
			HkStruct->Index = InitPhase;
			InitPhase++;
			if(TargetName != 0)
			{
				hkSetTargetExeName(TargetName);
				HkStruct->TProcessId = (DWORD)GetPidByName(TargetName);
			}
			return true;
		}
	}
	return false;
}
*/
__declspec(naked) void HK_MOV(PCLLHook HkParams)
{
	__asm
	{
		mov		   edi,edi
		push	   ebp
		mov		   ebp,esp
		mov		   eax,HkParams
		mov		   esi,[eax]HkParams.hkTAddress
		mov        al,byte ptr [eax]HkParams.Opcode
		mov        byte ptr [esi],al
		mov        ebx,[eax]HkParams.hkAddress
		add        esi,5
		sub        ebx,esi
		sub        esi,4
		mov        dword ptr [esi],ebx
		ret
	}
}
__declspec(naked) void  HK_CMPXCHG(PCLLHook HkParams)
{
	__asm
	{
		mov        eax,HkParams
		mov        esi,[eax]HkParams.hkTAddress//Source
		sub        ebp,8
		mov        ecx,[ebp]
		push       eax
		mov        al,byte ptr [eax]HkParams.Opcode
		mov        byte ptr [esi],al
		pop        eax
		mov        ebx,[eax]HkParams.hkAddress
		add        esi,5
		sub        ebx,esi
		sub        esi,4
		mov        dword ptr [ecx],ebx
		mov        ebx,dword ptr [ecx]
		mov        eax,[ecx]
mxchg:
		lock cmpxchg dword ptr [esi],ebx
		jne  mxchg 
		ret
	}
}
__declspec(naked) ULONG HookHandler(PEXCEPTION_POINTERS ExceptionInfo)   
{
	__asm
	{
TargetFuncs:
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
HookFuncs:
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
Int3Buffer:
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		nop
		xor  ecx,ecx
		mov  ebx,dword ptr [ExceptionInfo]
		mov  eax,dword ptr[ebx]ExceptionInfo.ExceptionRecord.ExceptionCode
		cmp  eax,0xC0000005
		je   FindAccessPoint
		mov	 eax,dword ptr[ebx]ExceptionInfo.ExceptionRecord.ExceptionCode
		cmp  eax,0x80000003
		je   FindBreakPoint
FindAccessPoint:
		cmp  ecx,10
		je   ContinueSearch
		mov  eax,4
		imul eax,ecx
		lea  edx,TargetFuncs
		mov  esi,dword ptr[edx+eax]
		cmp  byte ptr [esi],0x90
		je   ContinueSearch
		cmp  esi,[ebx]ExceptionInfo.ContextRecord.Eip
		je   FoundGp
		inc  ecx
		jmp  FindAccessPoint
FoundGp:
		lea  esi,HookFuncs
		mov  esi,dword ptr [esi+eax]
		cmp  byte ptr[esi],0x90
		mov  dword ptr[ebx]ExceptionInfo.ContextRecord.Eip,esi
		mov  eax,-1
		ret
FindBreakPoint:
		cmp  ecx,10
		je   ContinueSearch
		mov  eax,4
		imul eax,ecx
		lea  esi,Int3Buffer
		mov  edx,dword ptr[esi+eax]
		cmp  byte ptr[edx],0x90
		je   ContinueSearch
		cmp  edx,dword ptr[ebx]ExceptionInfo.ContextRecord.Eip
		je   FoundBp
		inc  ecx
		inc	 ecx
		jmp  FindBreakPoint
FoundBp:
		inc ecx
		mov eax,4
		imul eax,ecx
		mov ecx,dword ptr[esi+eax]
		cmp byte ptr[ecx],0x90
		je ContinueSearch
		mov ebx,[ebx]ExceptionInfo.ContextRecord.Eip
		mov dword ptr [ebx],ecx
		mov eax,-1
		ret
ContinueSearch:
		mov eax,0
		ret
	}
}
/*
			struct CLLHook HkParams = *(CLLHook*)HkTempPar;
			ClientId.UniqueProcess = (HANDLE)HkParams.TProcessId;
			ClientId.UniqueThread = 0;
			if(mbi.AllocationProtect & PAGE_EXECUTE_READWRITE)
			{
				__asm jmp sswitch;
			}
			else
			{
				pHolder = (PVOID)HkParams.hkTAddress;
				ProtectSize = HkParams.hkSz;
				if(NT_SUCCESS(NtProtectVirtualMemory(hProcess,&pHolder,&ProtectSize,PAGE_EXECUTE_READWRITE,&oProt)))
				{ 
sswitch:
					switch (HkType)
					{
						case HKMOV:
							ProtectSize = (ULONG)GetFunctionLength(HK_MOV);
							if(NT_SUCCESS(NtAllocateVirtualMemory(hProcess,&pHolder,0,&ProtectSize,MEM_COMMIT,PAGE_EXECUTE_READWRITE)))
							{
								if(NT_SUCCESS(NtWriteVirtualMemory(hProcess,pHolder,&HK_MOV,ProtectSize,&oProt)))
								{
									if(NT_SUCCESS(RtlCreateUserThread(hProcess,0,false,0,0,0,(PUSER_THREAD_START_ROUTINE)pHolder,&HkParams,&hThread,&ClientId)))
									{
										return true;
									}
								}
							}
							return false;
						case HKCMPXCHG:
							ProtectSize = (ULONG)GetFunctionLength(HK_CMPXCHG);
							if(NT_SUCCESS(NtAllocateVirtualMemory(hProcess,&pHolder,0,&ProtectSize,MEM_COMMIT,PAGE_EXECUTE_READWRITE)))
							{
								if(NT_SUCCESS(NtWriteVirtualMemory(hProcess,pHolder,&HK_CMPXCHG,ProtectSize,&oProt)))
								{
									if(NT_SUCCESS(RtlCreateUserThread(hProcess,0,false,0,0,0,(PUSER_THREAD_START_ROUTINE)pHolder,&HkParams,&hThread,&ClientId)))
									{
										return true;
									}
								}
							}
							return false;
					}
				}
			}
		}
		return false;
	}
   */
	bool SinSrvSetupVeHijack(__inout VEH_HIJACK_SETUP*HijackSetup)
	{
		ULONG Address = 0;
		BYTE FindThis[] = {0x89, 0x06, 0x00, 0x04};
		BYTE FindThis2[] = {0x89 ,0x46, 0x0, 0x5};
		HijackSetup->Alloc = (RTLALLOCATEHEAP)Native_GetApi(L"ntdll.dll","RtlAllocateHeap");
		HijackSetup->CriticalEnter = (RTLENTERCRITICALSECTION)Native_GetApi(L"ntdll.dll","RtlEnterCriticalSection");
		HijackSetup->Encode = (RTLENCODEPOINTER)Native_GetApi(L"ntdll.dll","RtlEncodePointer");
		HijackSetup->CriticalLeave = (RTLLEAVECRITICALSECTION)Native_GetApi(L"ntdll.dll","RtlLeaveCriticalSection");
		Address = (ULONG)Native_GetApi(L"ntdll.dll","RtlAddVectoredExceptionHandler");
		HijackSetup->VehListHead = FindCode((ULONG)Address,(BYTE*)&FindThis);
		HijackSetup->RtlpVectoredExceptionLock = FindCode(Address,(BYTE*)&FindThis2);
		if(!HijackSetup->Alloc && !HijackSetup->CriticalEnter && !HijackSetup->Encode && !HijackSetup->CriticalLeave && !HijackSetup->VehListHead && !HijackSetup->RtlpVectoredExceptionLock)
		{
			return false;
		}
		return true;
	}
	void SinSrvHijackVEH(__in VEH_HIJACK_SETUP*HijackSetup)
	{
		__asm
		{
RTL_HEAP:
			nop
			nop
			nop
			nop
RTL_ENCODED:
			nop
			nop
			nop
			nop
		}
		HijackSetup->Alloc(NtCurrentTeb()->ProcessEnvironmentBlock->ProcessHeap,0,sizeof(RTL_VECTORED_EXCEPTION_HANDLER));
		__asm
		{
			lea ecx, RTL_HEAP
			mov dword ptr[ecx],eax
		}
		if(NT_SUCCESS(HijackSetup->CriticalEnter((PRTL_CRITICAL_SECTION)HijackSetup->RtlpVectoredExceptionLock)))
		{
			__asm
			{
				lea edx,HijackSetup
				push eax
				push edx
				push [edx]HijackSetup.VectoredHandler
				call [edx]HijackSetup.Encode
				cmp eax, 0
				je Fail
				mov ecx,eax
				pop edx
				pop eax
				add eax,8
				mov dword ptr[eax],ecx
				mov ecx,dword ptr[edx]HijackSetup.VehListHead
				push ecx
				lea eax,RTL_HEAP
				push eax
				call InsertHeadList
			}
			if(NT_SUCCESS(HijackSetup->CriticalLeave((PRTL_CRITICAL_SECTION)HijackSetup->RtlpVectoredExceptionLock)))
			{
				return;
			}
Fail:
			return;
		}
	}
	typedef struct _THREAD_INFORMATION
	{
		_THREAD_INFORMATION *Prev;
		_THREAD_INFORMATION *Next;
		ULONG NumOfThreads;
		BOOL Suspended;
		CLIENT_ID ClientId;
		CONTEXT ThreadContext;
	}THREAD_INFORMATION,*PTHREAD_INFORMATION;

	BOOLEAN CheckForClientThread(THREAD_INFORMATION *ClientThreads,HANDLE ThreadId)
	{
		THREAD_INFORMATION *Temp = {0};
		Temp = ClientThreads;
		if(ClientThreads->NumOfThreads == 0)
		{
			return FALSE;
		}
		else
		{
			do
			{
				if(ClientThreads->ClientId.UniqueThread == ThreadId)
				{
					ClientThreads = Temp; 
					return TRUE;
				}
				if(ClientThreads->Prev)
				{
					ClientThreads = ClientThreads->Prev;
				}
			}while(ClientThreads->Prev != 0);
			ClientThreads = Temp;
			return FALSE;
		}
	}
	ULONG SuspendSiblings(ULONG UniqueProcess, ULONG UniqueThread, BOOL bSuspend,THREAD_INFORMATION *ClientThreads)
	{
		THREADENTRY32 te32;
		HANDLE hThread = INVALID_HANDLE_VALUE;
		HANDLE hSnapshot = INVALID_HANDLE_VALUE;
		BOOL bThread = FALSE;
		hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, UniqueProcess);
		if(hSnapshot != INVALID_HANDLE_VALUE) 
		{
			te32.dwSize = sizeof(THREADENTRY32);
			bThread = Thread32First(hSnapshot, &te32);
			do
			{
				if (te32.th32OwnerProcessID == UniqueProcess) 
				{
					if(UniqueThread != te32.th32ThreadID)
					{
						if(CheckForClientThread(ClientThreads,(HANDLE)te32.th32ThreadID) == FALSE && !ClientThreads->NumOfThreads > 0)
						{
							ClientThreads->ClientId.UniqueProcess = (HANDLE)UniqueProcess;
							ClientThreads->ClientId.UniqueThread = (HANDLE)te32.th32ThreadID;
							ClientThreads->NumOfThreads++;
						}
						else
						{
							ClientThreads->Next = (THREAD_INFORMATION*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(THREAD_INFORMATION));
							ClientThreads->Next->NumOfThreads = ClientThreads->NumOfThreads++;
							ClientThreads->Next->Prev = ClientThreads;							
							ClientThreads = ClientThreads->Next;
							ClientThreads->ClientId.UniqueProcess = (HANDLE)UniqueProcess;
							ClientThreads->ClientId.UniqueThread = (HANDLE)te32.th32ThreadID;
						}
						hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, te32.th32ThreadID);
						if (hThread != NULL) 
						{
							if(bSuspend)
							{
								if(SuspendThread(hThread) != -1)
								{
									ClientThreads->Suspended++;
									ClientThreads->ThreadContext.ContextFlags = CONTEXT_FULL;
									GetThreadContext(hThread,&ClientThreads->ThreadContext);
								}
							}
							else
							{
								if(ResumeThread(hThread) != -1)
								{
									ClientThreads->Suspended--;
								}
							}
						}
						CloseHandle(hThread);
					}
				}
			}while(Thread32Next(hSnapshot, &te32));
			CloseHandle(hSnapshot);
		}
		return 0;
	}
}
	
